package top.healthylife.gateway.platform.tc.api.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import top.healthylife.basics.utils.exception.BusinessException;
import top.healthylife.basics.utils.utils.SystemThreadLocal;
import top.healthylife.gateway.core.util.SystemConfigUtils;
import top.healthylife.gateway.dto.request.req.ApiReqDto;
import top.healthylife.gateway.platform.tc.api.config.SystemConfig;
import top.heathylife.gateway.common.cons.SystemCons;
import top.heathylife.gateway.common.po.RecordRequestInfo;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * @author YQ_Gao
 * @date 2021-9-13
 */
@Slf4j
public class TcHttpUtil {

    /**
     * 登录客户管理中心可查看获取appId和tokenId
     */
    private final static String SUCCESS = "0";

    private static final Map<String, String> ERROR_CODE = new HashMap<>(16);

    static {
        ERROR_CODE.put("0", "成功");
        ERROR_CODE.put("1", "系统错误");
        ERROR_CODE.put("2", "参数错误");
        ERROR_CODE.put("3", "数据异常，未能获取结果");
        ERROR_CODE.put("4", "⽤户不存在或配置错误");
        ERROR_CODE.put("5", "TokenKey验证失败");
        ERROR_CODE.put("6", "接⼜未定义或停⽌使⽤");
        ERROR_CODE.put("7", "⽤户没有接⼜使⽤权限");
        ERROR_CODE.put("8", "⽤户接⼜暂停使⽤");
        ERROR_CODE.put("9", "⽤户余额不⾜");
        ERROR_CODE.put("10", "系统繁忙，请稍候再试");
    }


    @SneakyThrows
    public static <T> T getApiData(String url, ApiReqDto reqDto, Class<T> cls) {
        // 接口地址，具体接口参见接口文档，每个接口有不同的url地址

        //1.获取业务参数
        Map<String, Object> param = BeanUtil.beanToMap(reqDto);
        //2.获取账号参数
        SystemConfig systemConfig = systemConfigInfo();
        // 构造所需入参 ,区分大小写
        param.put("authId", "1");
        param.put("isCpt", "1");
        param.put("tmcName", systemConfig.getTmcName());

        // 生成TokenKey
        // 注意：进行MD5摘要时，不能传入appId参数
        String tokenKey = getTokenKey(url, systemConfig.getTokenId(), param);
        param.put("tokenKey", tokenKey);

        // 注意：appId参数需要在请求的时候作为入参传入，appId不参与MD5摘要
        param.put("appId", systemConfig.getAppId());

        // http的post请求
        RecordRequestInfo.recordRequest(url, JSONUtil.toJsonStr(param), null, "post");
        String result = HttpClientUtil.doPost(url, param);
        log.info("天创返回结果:{}", result);
        // 记录三方请求元数据
        SystemThreadLocal.set(SystemCons.ORIGIN_DATA, result);
        try {
            JSONObject jsonObject = JSONObject.parseObject(result);
            String status = jsonObject.getString("status");
            if(status.equals(SUCCESS)){
               return jsonObject.toJavaObject(cls);
            }

            if(ERROR_CODE.containsKey(status)){
                throw new BusinessException(ERROR_CODE.get(status));
            }else{
                String message = jsonObject.getString("message");
                throw new BusinessException("未知code:{},异常信息:{}",message);
            }
        } catch (Exception e) {
            throw new BusinessException("天创响应异常:{}", e.getMessage());
        }
    }

    /**
     * 生成TokenKey
     *
     * @param url     接口url
     * @param tokenId token
     * @param param   参数
     * @return 摘要
     */
    public static String getTokenKey(String url, String tokenId, Map<String, Object> param) {
        String paramStr = sortParam(param);
        return md5Hex(url + tokenId + paramStr);
    }

    /**
     * 生成参数字符串，参数key按字典序排列
     *
     * @param param 参数
     * @return 参数拼接成字符串
     */
    public static String sortParam(Map<String, Object> param) {
        if (null == param || 0 == param.size()) {
            return "";
        }
        // 排序键，按照字母先后进行排序
        Iterator<String> iterator = param.keySet().iterator();
        String[] arr = new String[param.size()];
        for (int i = 0; iterator.hasNext(); i++) {
            arr[i] = iterator.next();
        }
        Arrays.sort(arr);
        // 生成进行MD5摘要的字符串
        StringBuilder sb = new StringBuilder();
        for (String key : arr) {
            String value = param.get(key) == null ? "" : param.get(key).toString();
            if (StringUtils.isNotBlank(value)) {
                sb.append(key).append("=").append(value).append(",");
            }
        }
        // 检查结果
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - 1);
        } else {
            return "";
        }
    }

    /**
     * 对字符串进行md5摘要，然后转化成16进制字符串
     * 使用标准的md5摘要算法
     *
     * @param text 字符串
     * @return 摘要
     */
    public static String md5Hex(String text) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(text.trim().getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte aByte : bytes) {
                int high = (aByte >> 4) & 0x0f;
                int low = aByte & 0x0f;
                sb.append(high > 9 ? (char) ((high - 10) + 'a') : (char) (high + '0'));
                sb.append(low > 9 ? (char) ((low - 10) + 'a') : (char) (low + '0'));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            System.out.println("系统不支持MD5算法");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 访问日志输出和配置获取
     *
     * @return 账号信息
     */
    public static SystemConfig systemConfigInfo() {
        //可直接通过工具类获取这个对象
        return (SystemConfig) SystemConfigUtils.get();
    }

}
